package com.ms.game.slot.base;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import com.xpec.c4.game.time.TimeSys;

public class SlotAnyWayCounter {
	
	/**
	 * wild盤面，若無wild 選項設定為0
	 */
	public static final int WILD_EMTPY =0;
	
	private HashMap<String , Way> bingoway = new  HashMap<String , Way>();
	
	/**
	 * way3 and way4暫時存放
	 */
	private HashMap<String , Way> temp3And4 = new  HashMap<String , Way>();
	
	private ArrayList<Way> list = new ArrayList<Way>();
	
	/**
	 * 記錄way bingo key
	 */
	private HashMap<String,Way> repeatWay = new HashMap<String,Way>();
	
	//遞迴是否停止
	private boolean isRemainStop = false; 
	
	/**
	 * screen 倒排
	 * @param reverseidx
	 * @param screen
	 * @return
	 */
	public ArrayList<Integer> reverse(int[][] reverseidx , ArrayList<Integer> screen)
	{
		ArrayList<Integer> rescreen = new ArrayList<Integer>(screen.size());
		for(int[] idxs:reverseidx)
		{
			for(int idx:idxs)
			{
				rescreen.add(screen.get(idx));
			}
		}
		return rescreen;
	}
			
	
	/**
	 * 讀取所有盤面的way -  僅適用於兩種symbol連線(中與不中)
	 * @param row
	 * @param col
	 * @param minBingoSize
	 * @return
	 */
	public ArrayList<Way> getAnyWay(int row , int col , int minBingoSize ,ArrayList<Integer> bingosymbol , ArrayList<Integer> screen)
	{
		list = new ArrayList<Way>();
		bingoway.clear();
		
		long starttime = TimeSys.currentTimeMills();
		
		for(int i=0;i<row;i++)
		{
			int idx = i * col;
			int symbol = screen.get(idx);
			if(!bingosymbol.contains(symbol))
			{
				continue;
			}
			
			remain(idx ,symbol, 1  ,row , col , minBingoSize,screen,new ArrayList<Integer>(col));
		}
		
		long end = TimeSys.currentTimeMills() - starttime;
		
		//System.out.println("total size="+list.size());
		
		list.addAll(temp3And4.values());
		bingoway.clear();
		temp3And4.clear();
		
		/*for(Way way:list)
		{
			System.out.println(way.toString());
		}
		System.out.println("total size1="+list.size());
		System.out.println("water time = "+end+" ms");*/
		return list;
	}
	
	/**
	 * 遞迴
	 * @param row
	 * @param col
	 * @param minBingoSize
	 * @param screen
	 */
	private boolean remain(int index ,int symbolid ,int deep  , int row , int col , int minBingoSize, ArrayList<Integer> screen , ArrayList<Integer> idxs)
	{
		int tmpdeep = deep;
		idxs.add(index);
		
		for(int i=0;i<row;i++)
		{
			int idx = deep + (i*col);
			
			if(idx==screen.size())
			{
				return false;
			}
			
			//symbolid 不對，但己滿足最小層數
			if(symbolid != screen.get(idx))
			{
				String key = Way.getKey(idxs);
				if(tmpdeep >= minBingoSize && !bingoway.containsKey(key))
				{
					Way way = new Way();
					way.count =idxs.size();
					way.symbolid = symbolid;
					way.screenidx.addAll(idxs);
					
					temp3And4.put(key, way);
					bingoway.put(key, way);
					
					setOtherResult(minBingoSize , col , idxs);
				}
				continue;
			}
			//滿足最大層數
			else if(symbolid == screen.get(idx) && tmpdeep == col)
			{
				String key = Way.getKey(idxs);
				if(!bingoway.containsKey(key))
				{
						Way way = new Way();
						way.count =idxs.size();
						way.symbolid = symbolid;
						way.screenidx.addAll(idxs);
						list.add(way);
						bingoway.put(key, way);
						setOtherResult(minBingoSize , col , idxs);
				}
				continue;
			}

			ArrayList<Integer> nextidxs = new ArrayList<Integer>(col);
			nextidxs.addAll(idxs);
			
			remain(idx ,screen.get(idx) , tmpdeep+1  ,row , col , minBingoSize,screen,nextidxs);
		}
		
		return false;
	}
	
	/**
	 * 讀取所有盤面的way - 僅適用於多種symbol連線
	 * @param row
	 * @param col
	 * @param minBingoSize
	 * @return
	 */
	public ArrayList<Way> getAnyWayAndWild(int row , int col , int minBingoSize ,ArrayList<Integer> bingosymbol , ArrayList<Integer> screen,ArrayList<Integer> wildscreen , int wildid)
	{
		ArrayList<Way> wlist = new ArrayList<Way>();
		bingoway.clear();
		
		//long starttime = TimeSys.currentTimeMills();
		for(int i=0;i<row;i++)
		{
			int idx = i;
			int symbol = screen.get(idx);
			int wildsyid = wildscreen.get(idx);
			if(
					!bingosymbol.contains(symbol)
					&&
					wildsyid != wildid
			)
			{
				continue;
			}
			
			//找出相同或有wildid
			ArrayList<ArrayList<Integer>> all = new ArrayList<ArrayList<Integer>>();
			for(int p=1;p<col;p++)
			{
				int start = p*row;
				int end = p*row + row;
				
				ArrayList<Integer> w =getSymbolIdx
				(	
								p,
								row,
								symbol,
								wildid,
								screen.subList(start,end),
								wildscreen.subList(start,end)
				);
				
				all.add(w);
			}
			
			
			wlist.addAll
			(
					getCombo
					(
							i ,
							symbol,
							minBingoSize ,
							col,
							all
					)
			);
		}
		
		/*long end = TimeSys.currentTimeMills() - starttime;
		for(Way way:list)
		{
			System.out.println(way.toString());
		}
		
		
		System.out.println("total size1="+list.size());
		System.out.println("water time = "+end+" ms");*/
		return wlist;
	}
	
	/**
	 * 查看所有index 是否有相同symbol or wild
	 * @param row
	 * @param symbol
	 * @param wildid
	 * @param wheelidx
	 * @param screen
	 * @param wildscreen
	 * @return
	 */
	private ArrayList<Integer> getSymbolIdx(int wheelidx   , int row , int symbol , int wildid , List<Integer> screen , List<Integer> wildscreen)
	{
		ArrayList<Integer> line = new ArrayList<Integer>();
		
		for(int i=0;i<row;i++)
		{
			int sy = screen.get(i);
			int wsy = wildscreen.get(i);
			if(sy==symbol || wsy==wildid)
			{
				line.add((wheelidx*row) + i);
			}
		}
		
		return line;
	}
	
	/**
	 * 找出有連線的idx
	 * @param col
	 * @param data
	 * @return
	 */
	private ArrayList<Way> getCombo(int symbolidx , int symbolid , int minsize , int col , ArrayList<ArrayList<Integer>> data)
	{
		ArrayList<Way> ways = new ArrayList<Way>();
		int maxdeep = 0;
		
		//第一層不用算
		for(int i=0;i<data.size();i++)
		{
			if(data.get(i).size()==0)
			{
				break;
			}
			
			maxdeep++;
		}
		
		if(maxdeep<minsize-1)
		{
			return ways;
		}
		
		int start = 0;
		ArrayList<ArrayList<Integer>> totalway  =  new ArrayList<ArrayList<Integer>>();
		ArrayList<Integer> wheelx =data.get(start);
		for(int idx:wheelx)
		{
				ArrayList<ArrayList<Integer>> childway = new ArrayList<ArrayList<Integer>>();
				ArrayList<Integer> way = new ArrayList<Integer>();
				way.add(symbolidx);
				way.add(idx);
				
			
				childway.add(way);
				
				remainWildList(start+1,maxdeep,childway,data,minsize);
				
				totalway.addAll(childway);
				childway.clear();
		}
		
		//合成WAY
		for(ArrayList<Integer> w:totalway)
		{
			Way way = new Way();
			way.count =w.size();
			way.symbolid = symbolid;
			way.screenidx.addAll(w);
			
			ways.add(way);
		}
		
		return ways;
	}
	
	
	private void remainWildList(int deep , int maxdeep , ArrayList<ArrayList<Integer>> ways , ArrayList<ArrayList<Integer>> data,int minsize)
	{
		if(deep>=maxdeep)
		{
			return;
		}
		
		ArrayList<ArrayList<Integer>> newWays = new ArrayList<ArrayList<Integer>>();
		for(ArrayList<Integer> v:ways)
		{
			for(int idx:data.get(deep))
			{
				ArrayList<Integer> clone = new ArrayList<Integer>();
				for(int vv:v)
				{
					clone.add(vv);
				}
				
				
				clone.add(idx);
				newWays.add(clone);
			}
		}
		
		if(newWays.size()==0)
		{
			for(ArrayList<Integer> v:ways)
			{
				if(v.size()>=minsize)
				{
					newWays.add(v);
				}
			}
		}
		
		
		ways.clear();
		ways.addAll(newWays);
		
		if(deep<=maxdeep)
		{
			remainWildList(deep+1,maxdeep,ways,data,minsize);
		}
	}
	
	
	/**
	 * 當超過最小中獎值時，將其他組合一起排除
	 * @param minsize
	 * @param maxsize
	 * @param idxs
	 */
	private void setOtherResult(int minsize , int maxsize , ArrayList<Integer> idxs)
	{
		if(idxs.size() - minsize <=0)
		{
			return;
		}
		
		for(int i=minsize;i<idxs.size();i++)
		{
				List<Integer> xn = idxs.subList(0, i);
				String key = Way.getKey(new ArrayList<Integer>(xn));
				
				if(temp3And4.containsKey(key))
				{
					temp3And4.remove(key);
				}
				
				bingoway.put(key, null);
		}
	}
	
	/**
	 * 排除重覆中獎way , 需先將way2 screen index正確
	 * @return
	 */
	public void removeDoubleWay(ArrayList<Way> w1 , ArrayList<Way> w2)
	{
		for(Way ww2:w2)
		{
			Collections.reverse(ww2.screenidx);
			repeatWay.put(Arrays.toString(ww2.screenidx.toArray()), ww2);
		}
		
		String key =null;
		for(Way ww1:w1)
		{
			key =  Arrays.toString(ww1.screenidx.toArray());
			if(repeatWay.containsKey(key))
			{
				repeatWay.remove(key);
			}
		}
		
		
		w1.addAll(repeatWay.values());
		repeatWay.clear();
	}
	
	
	public static void main(String[] args) 
	{
		int [][]  reverseidx =
		{
				{20,21,22,23,24},
				{15,16,17,18,19},
				{10,11,12,13,14},
				{5,6,7,8,9},
				{0,1,2,3,4}
				
		};
		
		//[10, 6, 3, 0, 0, 11, 7, 4, 7, 10, 1, 8, 5, 8, 3, 2, 9, 10, 9, 0, 3, 10, 7, 10, 5]

		/*Integer[] screen_symbol = 
		{
				10, 6, 3, 0, 0, 
				11, 7, 4, 7, 10, 
				1, 8, 5, 8, 3, 
				2, 9, 10, 9, 0, 
				3, 10, 7, 10, 5
		};*/
		
		/*Integer[] screen_symbol = 
			{
					1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1
			};
		*/
		
		Integer[] screen_symbol = 
		{
				1, 2, 3, 7, 10,
				1, 2, 3, 7, 10,
				5, 11, 3, 7, 10,
				5, 11, 3, 7, 10,
		};
		
		
		//[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 9, 0, 0, 0, 0, 0, 0]
		Integer[] wild_symbol = 
		{
				0, 0, 0, 0, 0, 
				0, 0, 0, 0, 0, 
				0, 0, 0, 0, 0, 
				0, 0, 0, 0, 0
		};
		
		
		Integer[] bingo_symbol = {1,2};
		
		List<Integer> ss = Arrays.asList(screen_symbol);
		List<Integer> bs = Arrays.asList(bingo_symbol);
		List<Integer> ws =  Arrays.asList(wild_symbol);
		
		ArrayList<Integer> screen = new ArrayList<Integer>(ss);
		ArrayList<Integer> bingosymbol = new ArrayList<Integer>(bs);
		ArrayList<Integer> wild = new ArrayList<Integer>(ws);
		//兩顆中獎
				/*ArrayList<Way> way2 =wayCounter.getAnyWayAndWild
				(	
								ZCJBSymbolType.MAX_ROW, 
								ZCJBSymbolType.MAX_COL , 
								MIN_BINGO_SPECSYMBOL_SIZE, 
								bingoSymbolHas2, 
								screendata.screen, 
								screendata.wild, 
								ZCJBSymbolType.WILD.getSymobl()
				);*/
		
		SlotAnyWayCounter counter = new SlotAnyWayCounter();
		
		//ArrayList<Integer> rescreen =counter.reverse(reverseidx, screen);
		//ArrayList<Integer> rewildscreen =counter.reverse(reverseidx, wild);
		
		ArrayList<Way> way = counter.getAnyWayAndWild(4, 5, 2, bingosymbol, screen,wild,11);
		
		System.out.println("way="+way.toString());
	}
}
